package dk.twu.analyzer.loader;

import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
import dk.twu.analyzer.model.Exchange;
import dk.twu.analyzer.model.ISymbol;
import dk.twu.analyzer.model.ITDRecord;
import dk.twu.analyzer.model.Symbol;
import dk.twu.analyzer.util.AnalyzerConfig;
import dk.twu.analyzer.util.DateTimeCleaner;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVParser;
import org.apache.commons.csv.CSVRecord;

import java.io.*;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class ITDDataLoader {
    private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("ddMMMyyyyHHmm");
    private final AnalyzerConfig config;

    public ITDDataLoader(AnalyzerConfig config) {
        this.config = config;
    }

    public Multimap<String, ITDRecord> loadITDRecords(ISymbol symbolList, Collection<Exchange> exchanges, LocalDate
            fromDate, LocalDate toDate) {
        Multimap<String, ITDRecord> itdRecordsMap = HashMultimap.create();
        exchanges.stream().forEach(ex -> {
            //Find ITD files for given exchange and given date range
            File[] files = MarketDataHelper.getFilesForExchange(config, MarketDataHelper.DataType.ITD, ex, Optional
                    .of(fromDate), Optional.of(toDate));
            //Load ITD records for each file
            Arrays.asList(files).stream().forEach(file -> {
                Collection<ITDRecord> itdRecords = loadITDRecordFromFile(symbolList, file, ex).collect(Collectors.toList());
                itdRecords.stream().forEach(record -> itdRecordsMap.put(record.getSymbol().getCode(), record));
            });
        });
        return itdRecordsMap;
    }



    public Map<Symbol, List<ITDRecord>> loadITDRecordsStream(ISymbol symbolList, Collection<Exchange> exchanges, LocalDate fromDate, LocalDate toDate) {

        Stream<ITDRecord> itdRecordStream = exchanges.stream().
                map(ex -> Arrays.stream(MarketDataHelper.getFilesForExchange(config, MarketDataHelper.DataType.ITD,
                        ex, Optional.of(fromDate), Optional.of(toDate))).
                        map(f -> loadITDRecordFromFile(symbolList, f, ex)).
                        flatMap(r -> r)).
                flatMap(r -> r);
        return itdRecordStream.collect(Collectors.groupingBy(ITDRecord::getSymbol, Collectors.toList()));
    }

    private Stream<ITDRecord> loadITDRecordFromFile(ISymbol allSymbols, File file, Exchange exchange) {
        Collection<ITDRecord> result = new ArrayList<>();
        try {
            Reader reader = new FileReader(file);
            CSVFormat format = CSVFormat.EXCEL.withHeader().withDelimiter(',');
            CSVParser parser = new CSVParser(reader, format);
            for (CSVRecord record : parser) {
                String symbolText = record.get("Symbol");
                String dateTimeText = record.get("Date").replace(" ", "").replace("-", "").replace(":", "");
                dateTimeText = DateTimeCleaner.clean(dateTimeText);
                LocalDateTime dateTime = LocalDateTime.parse(dateTimeText, DATE_TIME_FORMATTER);
                String openText = record.get("Open");
                String highText = record.get("High");
                String lowText = record.get("Low");
                String closeText = record.get("Close");
                String volumeText = record.get("Volume");
                Optional<Symbol> symbol = allSymbols.getSymbol(symbolText + "." + exchange.getCode());
                if (symbol.isPresent()) {
                    result.add(new ITDRecord(symbol.get(), Double.valueOf(openText), Double.valueOf(highText), Double
                            .valueOf(lowText), Double.valueOf(closeText), Long.valueOf(volumeText), dateTime));
                }
            }
            reader.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result.stream();
    }
}
